package com.lxw.manage_cms.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lxw.framework.domain.cms.CmsPage;
import com.lxw.framework.domain.cms.CmsSite;
import com.lxw.framework.domain.cms.CmsTemplate;
import com.lxw.framework.domain.cms.request.QueryPageRequest;
import com.lxw.framework.domain.cms.response.CmsCode;
import com.lxw.framework.domain.course.response.CmsPostPageResult;
import com.lxw.framework.exception.CustomException;
import com.lxw.framework.model.response.CommonCode;
import com.lxw.manage_cms.config.Config;
import com.lxw.manage_cms.dao.CmsPageDao;
import com.lxw.manage_cms.dao.CmsSiteDao;
import com.lxw.manage_cms.dao.CmsTemplateDao;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Service
@Slf4j
public class CmsPageServiceImpl implements ICmsPageService {
    @Autowired
    CmsPageDao cmsPageDao;
    @Autowired
    CmsTemplateDao cmsTemplateDao;

    @Autowired
    RestTemplate restTemplate;
    @Autowired
    GridFsTemplate gridFsTemplate;
    @Autowired
    GridFSBucket gridFSBucket;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    CmsSiteDao cmsSiteDao;

    @Override
    public Page<CmsPage> findList(Integer page, Integer pageSize, QueryPageRequest qpr) {
        CmsPage cmsPage = new CmsPage();
        if (StringUtils.isNotEmpty(qpr.getTemplateId())) {
            cmsPage.setTemplateId(qpr.getTemplateId());
        }
        if (StringUtils.isNotEmpty(qpr.getSiteId())) {
            cmsPage.setSiteId(qpr.getSiteId());
        }
        if (StringUtils.isNotEmpty(qpr.getPageAliase())) {
            cmsPage.setPageAliase(qpr.getPageAliase());//"" null
        }

        // 页面别名模糊匹配
        ExampleMatcher.GenericPropertyMatcher contains = ExampleMatcher.GenericPropertyMatchers.contains();
        ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("pageAliase", contains);
        Example<CmsPage> example = Example.of(cmsPage, exampleMatcher);

        //页码从0开始
        page -= 1;
        PageRequest of = PageRequest.of(page, pageSize);
        Page<CmsPage> all = cmsPageDao.findAll(example, of);

        return all;
    }

    @Override
    public CmsPage save(CmsPage cmsPage) {
        // 1.创建页面名称、站点Id、页面webpath为唯一索引
        long count = getPageCnt(cmsPage);
        if (count > 0) {
//            throw new RuntimeException("创建页面名称、站点Id、页面webpath为唯一");
            throw new CustomException(CmsCode.CMS_PAGE_ISMUSTONE);
        }

        // 2.保存
       return cmsPageDao.save(cmsPage);
    }

    private long getPageCnt(CmsPage cmsPage) {
        CmsPage cmsPage2 = new CmsPage();
        cmsPage2.setPageName(cmsPage.getPageName());
        cmsPage2.setSiteId(cmsPage.getSiteId());
        cmsPage2.setPageWebPath(cmsPage.getPageWebPath());
        Example<CmsPage> example = Example.of(cmsPage2);
        return cmsPageDao.count(example);
    }

    /**
     * 根据Id获取页面信息
     *
     * @param pageId
     * @return
     */
    @Override
    public CmsPage findById(String pageId) {
        Optional<CmsPage> byId = cmsPageDao.findById(pageId);
        if (byId.isPresent()) {
            return byId.get();
        }
        return null;
    }

    @Override
    public void edit(String pageId, CmsPage cmsPage) {
        // 1查询
        Optional<CmsPage> byId = cmsPageDao.findById(pageId);
        if (!byId.isPresent()) {
//           throw new RuntimeException("");
            throw new CustomException(CmsCode.CMS_PAGE_NAMEISNULL);
        }

        CmsPage page = byId.get();
        // 2更新 （注意：必选判断非空和空字符）
        String pageName = page.getPageName();
        if (StringUtils.isNotEmpty(cmsPage.getSiteId())) {
            page.setSiteId(cmsPage.getSiteId());
        }

        if (StringUtils.isNotEmpty(cmsPage.getTemplateId())) {
            page.setTemplateId(cmsPage.getTemplateId());
        }

        if (StringUtils.isNotEmpty(cmsPage.getPageName())) {
            page.setPageName(cmsPage.getPageName());
        }
        if (StringUtils.isNotEmpty(cmsPage.getPageAliase())) {
            page.setPageAliase(cmsPage.getPageAliase());
        }
        if (StringUtils.isNotEmpty(cmsPage.getPageWebPath())) {
            page.setPageWebPath(cmsPage.getPageWebPath());
        }

        if (StringUtils.isNotEmpty(cmsPage.getPagePhysicalPath())) {
            page.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
        }

        if (StringUtils.isNotEmpty(cmsPage.getPageType())) {
            page.setPageType(cmsPage.getPageType());
        }

        if (StringUtils.isNotEmpty(cmsPage.getDataUrl())) {
            page.setDataUrl(cmsPage.getDataUrl());
        }
        // 3.创建页面名称、站点Id、页面webpath为唯一索引
        if (StringUtils.isNotEmpty(cmsPage.getPageName()) && !cmsPage.getPageName().equals(pageName)) {
            long count = getPageCnt(page);
            if (count > 0) {
//                throw new RuntimeException("创建页面名称、站点Id、页面webpath为唯一");
                throw new CustomException(CmsCode.CMS_PAGE_ISMUSTONE);
            }
        }

        cmsPageDao.save(page);

    }

    @Override
    public void delById(String pageId) {
        cmsPageDao.deleteById(pageId);
    }

    @Override
    public String preview(String pageId) {

        // 1. 根据ID 获取页面信息
        CmsPage cmsPage = findById(pageId);
        if(cmsPage==null){
            log.error("pageId:{},不存在",pageId);
            throw new CustomException(CommonCode.FAIL);
        }

        // 2. 获取dataUrl并且远程获取模型数据
        String dataUrl = cmsPage.getDataUrl();
        if (StringUtils.isEmpty(dataUrl)) {
            throw new CustomException(CommonCode.FAIL);
        }
        String forObject = restTemplate.getForObject(dataUrl, String.class);
        JSONObject jsonObject = JSON.parseObject(forObject);

        // 3. 获取模版
        String templateId = cmsPage.getTemplateId();
        Optional<CmsTemplate> byId = cmsTemplateDao.findById(templateId);
        if (!byId.isPresent()) {
            throw new CustomException(CommonCode.FAIL);
        }
        CmsTemplate cmsTemplate = byId.get();
        String templateFileId = cmsTemplate.getTemplateFileId();
        String tempStr = getTempStr(templateFileId);


        // 4. 执行静态化
        Template template = getTemplate(tempStr);
        String htmlStr = null;
        try {
            // new HashMap map.put("map","");

            htmlStr = FreeMarkerTemplateUtils.processTemplateIntoString(template, jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
        }


        return htmlStr;
    }

    @Override
    public void postPage(String pageId) {
        // 1 页面静态化
        CmsPage cmsPage = findById(pageId);
        String previewHtml = this.preview(pageId);

        // 2 保存静态化页面到gridFs
        try {
            InputStream inputStream = IOUtils.toInputStream(previewHtml, "UTF-8");
            String fileName = cmsPage.getPageName();
            // 保存文件到gridFs
            ObjectId store = gridFsTemplate.store(inputStream, fileName);

            cmsPage.setHtmlFileId(String.valueOf(store));//静态化页面文件ID
            cmsPageDao.save(cmsPage); //更新
        } catch (IOException e) {
            e.printStackTrace();
            throw new CustomException(CommonCode.FAIL);
        }

        // 3.写入磁盘 MQ
        // {"pageId":"33333"}
        Map<String,Object> map = new HashMap<>();
        map.put("pageId",pageId);

        //
        String routingKey = cmsPage.getSiteId();// 站点ID
        // 发送消息队列 写入磁盘
        rabbitTemplate.convertAndSend(Config.EXCHANGE_NAME,routingKey,JSON.toJSONString(map));
    }

    @Override
    public CmsPostPageResult postPageQuick(CmsPage cmsPage) {
        // 1.保存页面信息
        CmsPage cmsPage1 = cmsPageDao.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId()
                , cmsPage.getPageWebPath());
        if(cmsPage1==null){
            // 插入数据
            this.save(cmsPage);
        }else {
            cmsPage.setPageId(cmsPage1.getPageId());
            cmsPageDao.save(cmsPage);
        }
        // 2. 页面发布
        this.postPage(cmsPage.getPageId());

        //3.页面 Url = cmsSite.siteDomain + cmsSite.siteWebPath + cmsPage.pageWebPath + cmsPage.pageName
        String pageUrl = null;
        Optional<CmsSite> byId = cmsSiteDao.findById(cmsPage.getSiteId());//查询站点信息
        if(!byId.isPresent()){
            throw new CustomException(CommonCode.FAIL);
        }

        CmsSite cmsSite = byId.get();
        pageUrl = cmsSite.getSiteDomain()+cmsSite.getSiteWebPath()
        +cmsPage.getPageWebPath()+cmsPage.getPageName();


        return new CmsPostPageResult(CommonCode.SUCCESS,pageUrl);
    }

    /**
     * 获取模板
     * @param tempStr
     * @return
     */
    private Template getTemplate(String tempStr) {
        try {
            String uuid = UUID.randomUUID().toString().replace("-","");
            Configuration configuration = new Configuration(Configuration.getVersion());
            StringTemplateLoader templateLoader = new StringTemplateLoader();
            templateLoader.putTemplate(uuid,tempStr);
            configuration.setTemplateLoader(templateLoader);

            configuration.setDefaultEncoding("UTF-8");//设置编码
            Template template = configuration.getTemplate(uuid);
            return template;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 读取gridFs模板文件
     * @param templateFileId
     * @return
     */
    private String getTempStr(String templateFileId) {
        try {
            // 1.获取集合
            GridFSFile gridFSFile = gridFsTemplate.findOne(
                    Query.query(Criteria.where("_id").is(templateFileId)));
            // 2. 获取文件块
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());

            // 3.获取文件合并流
            GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
            String tempStr = IOUtils.toString(gridFsResource.getInputStream(), "UTF-8");
            return tempStr;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
